"""
财务数据可视化模块
基于PRD精简版的图表设计要求
"""

import plotly.graph_objects as go
import plotly.express as px
from plotly.subplots import make_subplots
import pandas as pd
import numpy as np
from typing import Dict, Any, List, Tuple
import logging

from config import CHART_CONFIG, SCORE_GRADES
from account_mapping import account_classifier, CATEGORY_DISPLAY_NAMES

logger = logging.getLogger(__name__)


class FinancialVisualizer:
    """财务数据可视化器"""
    
    def __init__(self):
        """初始化可视化器"""
        self.chart_config = CHART_CONFIG
        self.color_scheme = CHART_CONFIG['color_scheme']
        self.display_names = CATEGORY_DISPLAY_NAMES
    
    def create_balance_sheet_chart(self, data: pd.DataFrame, stock_code: str) -> go.Figure:
        """
        创建资产负债表堆叠柱状图
        
        Args:
            data: 包含分类信息的财务数据
            stock_code: 股票代码
            
        Returns:
            Plotly图表对象
        """
        if data.empty:
            return self._create_empty_chart("暂无数据")
        
        try:
            # 数据预处理
            chart_data = self._prepare_chart_data(data)
            
            # 创建子图
            fig = make_subplots(
                rows=1, cols=3,
                subplot_titles=('资产', '负债', '所有者权益'),
                specs=[[{"secondary_y": False}, {"secondary_y": False}, {"secondary_y": False}]],
                horizontal_spacing=0.05
            )
            
            # 添加资产数据
            self._add_assets_traces(fig, chart_data, col=1)
            
            # 添加负债数据
            self._add_liabilities_traces(fig, chart_data, col=2)
            
            # 添加权益数据
            self._add_equity_traces(fig, chart_data, col=3)
            
            # 更新布局
            self._update_chart_layout(fig, stock_code)
            
            return fig
            
        except Exception as e:
            logger.error(f"创建图表失败: {e}")
            return self._create_empty_chart("图表创建失败")
    
    def _prepare_chart_data(self, data: pd.DataFrame) -> pd.DataFrame:
        """准备图表数据"""
        # 按分类聚合数据
        aggregated = account_classifier.aggregate_by_category(data)
        
        # 转换金额单位为亿元
        aggregated['金额_亿元'] = aggregated['金额'] / 100000000
        
        # 添加显示名称
        aggregated['category_display'] = aggregated['category'].map(self.display_names)
        
        # 按日期排序
        aggregated = aggregated.sort_values('报告日期')
        
        return aggregated
    
    def _add_assets_traces(self, fig: go.Figure, data: pd.DataFrame, col: int):
        """添加资产类数据"""
        asset_categories = [
            'cash_equivalents', 'receivables', 'prepayments', 
            'inventory', 'other_current_assets',
            'long_term_investments', 'fixed_assets', 
            'intangible_goodwill', 'other_non_current_assets'
        ]
        
        colors = self.color_scheme['assets'] * 3  # 确保颜色足够
        
        for i, category in enumerate(asset_categories):
            category_data = data[data['category'] == category]
            
            if not category_data.empty:
                fig.add_trace(
                    go.Bar(
                        x=category_data['报告日期'],
                        y=category_data['金额_亿元'],
                        name=self.display_names.get(category, category),
                        marker_color=colors[i % len(colors)],
                        hovertemplate='<b>%{fullData.name}</b><br>' +
                                    '日期: %{x}<br>' +
                                    '金额: %{y:.2f}亿元<extra></extra>',
                        showlegend=True
                    ),
                    row=1, col=col
                )
    
    def _add_liabilities_traces(self, fig: go.Figure, data: pd.DataFrame, col: int):
        """添加负债类数据"""
        liability_categories = [
            'short_term_debt', 'payables', 'advance_receipts',
            'accrued_expenses', 'other_current_liabilities',
            'long_term_debt', 'other_non_current_liabilities'
        ]
        
        colors = self.color_scheme['liabilities'] * 3
        
        for i, category in enumerate(liability_categories):
            category_data = data[data['category'] == category]
            
            if not category_data.empty:
                fig.add_trace(
                    go.Bar(
                        x=category_data['报告日期'],
                        y=category_data['金额_亿元'],
                        name=self.display_names.get(category, category),
                        marker_color=colors[i % len(colors)],
                        hovertemplate='<b>%{fullData.name}</b><br>' +
                                    '日期: %{x}<br>' +
                                    '金额: %{y:.2f}亿元<extra></extra>',
                        showlegend=True
                    ),
                    row=1, col=col
                )
    
    def _add_equity_traces(self, fig: go.Figure, data: pd.DataFrame, col: int):
        """添加权益类数据"""
        equity_categories = [
            'share_capital', 'capital_reserves', 
            'retained_earnings', 'other_equity'
        ]
        
        colors = self.color_scheme['equity'] * 2
        
        for i, category in enumerate(equity_categories):
            category_data = data[data['category'] == category]
            
            if not category_data.empty:
                fig.add_trace(
                    go.Bar(
                        x=category_data['报告日期'],
                        y=category_data['金额_亿元'],
                        name=self.display_names.get(category, category),
                        marker_color=colors[i % len(colors)],
                        hovertemplate='<b>%{fullData.name}</b><br>' +
                                    '日期: %{x}<br>' +
                                    '金额: %{y:.2f}亿元<extra></extra>',
                        showlegend=True
                    ),
                    row=1, col=col
                )
    
    def _update_chart_layout(self, fig: go.Figure, stock_code: str):
        """更新图表布局"""
        fig.update_layout(
            title={
                'text': f'{stock_code} 资产负债表结构分析',
                'x': 0.5,
                'font': {'size': self.chart_config['title_size']}
            },
            height=self.chart_config['height'],
            barmode='stack',
            font={'family': self.chart_config['font_family']},
            legend={
                'orientation': 'h',
                'yanchor': 'bottom',
                'y': -0.2,
                'xanchor': 'center',
                'x': 0.5,
                'font': {'size': self.chart_config['legend_size']}
            },
            margin={'l': 50, 'r': 50, 't': 80, 'b': 100}
        )
        
        # 更新y轴标题
        fig.update_yaxes(title_text="金额 (亿元)", title_font_size=self.chart_config['axis_title_size'])
        fig.update_xaxes(title_text="报告期", title_font_size=self.chart_config['axis_title_size'])
    
    def create_score_gauge_chart(self, score: float, grade: Dict[str, str]) -> go.Figure:
        """
        创建评分仪表盘图表
        
        Args:
            score: 评分数值
            grade: 评分等级信息
            
        Returns:
            Plotly仪表盘图表
        """
        # 确定颜色
        if score >= 80:
            color = "green"
        elif score >= 60:
            color = "yellow"
        else:
            color = "red"
        
        fig = go.Figure(go.Indicator(
            mode="gauge+number+delta",
            value=score,
            domain={'x': [0, 1], 'y': [0, 1]},
            title={'text': f"价值投资评分<br><span style='font-size:0.8em;color:gray'>{grade['description']}</span>"},
            delta={'reference': 70},
            gauge={
                'axis': {'range': [None, 100]},
                'bar': {'color': color},
                'steps': [
                    {'range': [0, 50], 'color': "lightgray"},
                    {'range': [50, 70], 'color': "gray"},
                    {'range': [70, 90], 'color': "lightgreen"},
                    {'range': [90, 100], 'color': "green"}
                ],
                'threshold': {
                    'line': {'color': "red", 'width': 4},
                    'thickness': 0.75,
                    'value': 90
                }
            }
        ))
        
        fig.update_layout(
            height=300,
            font={'size': 14}
        )
        
        return fig
    
    def create_metrics_comparison_chart(self, metrics: Dict[str, Any]) -> go.Figure:
        """
        创建关键指标对比图表
        
        Args:
            metrics: 财务指标字典
            
        Returns:
            Plotly雷达图
        """
        # 选择关键指标
        key_metrics = {
            '现金比例': metrics.get('cash_ratio', 0) * 100,
            '流动比率': min(metrics.get('current_ratio', 0) * 50, 100),  # 标准化到100
            '资产负债率': 100 - metrics.get('debt_ratio', 0) * 100,  # 反向，越低越好
            '应收账款占比': 100 - metrics.get('receivables_ratio', 0) * 100,  # 反向
            '总资产增长': 50 + metrics.get('total_asset_growth', 0) * 100,  # 基准50
        }
        
        categories = list(key_metrics.keys())
        values = list(key_metrics.values())
        
        fig = go.Figure()
        
        fig.add_trace(go.Scatterpolar(
            r=values,
            theta=categories,
            fill='toself',
            name='当前指标',
            line_color='blue'
        ))
        
        fig.update_layout(
            polar=dict(
                radialaxis=dict(
                    visible=True,
                    range=[0, 100]
                )),
            showlegend=True,
            title="关键财务指标雷达图",
            height=400
        )
        
        return fig
    
    def create_trend_chart(self, data: pd.DataFrame, metric: str) -> go.Figure:
        """
        创建趋势线图表
        
        Args:
            data: 时间序列数据
            metric: 指标名称
            
        Returns:
            Plotly线图
        """
        if data.empty:
            return self._create_empty_chart(f"暂无{metric}数据")
        
        fig = go.Figure()
        
        fig.add_trace(go.Scatter(
            x=data['报告日期'],
            y=data[metric],
            mode='lines+markers',
            name=metric,
            line=dict(width=3),
            marker=dict(size=8)
        ))
        
        fig.update_layout(
            title=f'{metric}趋势分析',
            xaxis_title='报告期',
            yaxis_title=metric,
            height=300,
            showlegend=False
        )
        
        return fig
    
    def _create_empty_chart(self, message: str) -> go.Figure:
        """创建空图表"""
        fig = go.Figure()
        
        fig.add_annotation(
            text=message,
            xref="paper", yref="paper",
            x=0.5, y=0.5,
            xanchor='center', yanchor='middle',
            font=dict(size=16, color="gray")
        )
        
        fig.update_layout(
            height=400,
            xaxis={'visible': False},
            yaxis={'visible': False}
        )
        
        return fig
    
    def create_data_table(self, data: pd.DataFrame) -> pd.DataFrame:
        """
        创建数据表格
        
        Args:
            data: 原始数据
            
        Returns:
            格式化后的DataFrame
        """
        if data.empty:
            return pd.DataFrame()
        
        # 选择显示的列
        display_columns = ['报告日期', '科目', '金额', 'category']
        available_columns = [col for col in display_columns if col in data.columns]
        
        table_data = data[available_columns].copy()
        
        # 格式化金额
        if '金额' in table_data.columns:
            table_data['金额(万元)'] = (table_data['金额'] / 10000).round(2)
            table_data = table_data.drop('金额', axis=1)
        
        # 添加分类显示名称
        if 'category' in table_data.columns:
            table_data['分类'] = table_data['category'].map(self.display_names)
            table_data = table_data.drop('category', axis=1)
        
        # 按日期和金额排序
        if '报告日期' in table_data.columns:
            table_data = table_data.sort_values(['报告日期', '金额(万元)'], ascending=[False, False])
        
        return table_data


# 全局可视化器实例
financial_visualizer = FinancialVisualizer()
